package net.jgrm.redisadvanced.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.jgrm.redisadvanced.config.RedisAdvancedProperties;
import net.jgrm.redisadvanced.service.RedisListService;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Redis List类型操作服务实现类
 */
@Slf4j
//@Service
public class RedisListServiceImpl implements RedisListService {

    //    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    //    @Autowired
    private RedisAdvancedProperties redisAdvancedProperties;

    //    @Autowired
    private ObjectMapper objectMapper;

    public RedisListServiceImpl(RedisTemplate<String, Object> redisTemplate, RedisAdvancedProperties redisAdvancedProperties, ObjectMapper objectMapper) {
        this.redisTemplate = redisTemplate;
        this.redisAdvancedProperties = redisAdvancedProperties;
        this.objectMapper = objectMapper;
    }

    /**
     * 添加前缀到键名
     */
    private String addPrefix(String key) {
        return redisAdvancedProperties.getKeyPrefix() + key;
    }

    @Override
    public Long leftPush(String key, Object... values) {
        try {
            Long result = redisTemplate.opsForList().leftPushAll(addPrefix(key), values);
            log.debug("List leftPush successful: key={}", key);
            return result;
        } catch (Exception e) {
            log.error("List leftPush error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis leftPush operation failed", e);
        }
    }

    @Override
    public Long rightPush(String key, Object... values) {
        try {
            Long result = redisTemplate.opsForList().rightPushAll(addPrefix(key), values);
            log.debug("List rightPush successful: key={}", key);
            return result;
        } catch (Exception e) {
            log.error("List rightPush error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis rightPush operation failed", e);
        }
    }

    @Override
    public <T> T leftPop(String key, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForList().leftPop(addPrefix(key));
            log.debug("List leftPop successful: key={}", key);
            return convertValue(value, clazz);
        } catch (Exception e) {
            log.error("List leftPop error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis leftPop operation failed", e);
        }
    }

    @Override
    public <T> T rightPop(String key, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForList().rightPop(addPrefix(key));
            log.debug("List rightPop successful: key={}", key);
            return convertValue(value, clazz);
        } catch (Exception e) {
            log.error("List rightPop error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis rightPop operation failed", e);
        }
    }

    @Override
    public <T> T leftPop(String key, long timeout, TimeUnit timeUnit, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForList().leftPop(addPrefix(key), timeout, timeUnit);
            log.debug("List blocking leftPop successful: key={}", key);
            return convertValue(value, clazz);
        } catch (Exception e) {
            log.error("List blocking leftPop error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis blocking leftPop operation failed", e);
        }
    }

    @Override
    public <T> T rightPop(String key, long timeout, TimeUnit timeUnit, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForList().rightPop(addPrefix(key), timeout, timeUnit);
            log.debug("List blocking rightPop successful: key={}", key);
            return convertValue(value, clazz);
        } catch (Exception e) {
            log.error("List blocking rightPop error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis blocking rightPop operation failed", e);
        }
    }

    @Override
    public Long size(String key) {
        try {
            Long result = redisTemplate.opsForList().size(addPrefix(key));
            log.debug("List size successful: key={}", key);
            return result;
        } catch (Exception e) {
            log.error("List size error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis list size operation failed", e);
        }
    }

    @Override
    public <T> List<T> range(String key, long start, long end, Class<T> clazz) {
        try {
            List<Object> values = redisTemplate.opsForList().range(addPrefix(key), start, end);
            log.debug("List range successful: key={}, start={}, end={}", key, start, end);
            return convertList(values, clazz);
        } catch (Exception e) {
            log.error("List range error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis list range operation failed", e);
        }
    }

    @Override
    public <T> T index(String key, long index, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForList().index(addPrefix(key), index);
            log.debug("List index successful: key={}, index={}", key, index);
            return convertValue(value, clazz);
        } catch (Exception e) {
            log.error("List index error: key={}, index={}, error={}", key, index, e.getMessage(), e);
            throw new RuntimeException("Redis list index operation failed", e);
        }
    }

    @Override
    public void set(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(addPrefix(key), index, value);
            log.debug("List set successful: key={}, index={}", key, index);
        } catch (Exception e) {
            log.error("List set error: key={}, index={}, error={}", key, index, e.getMessage(), e);
            throw new RuntimeException("Redis list set operation failed", e);
        }
    }

    @Override
    public Long remove(String key, long count, Object value) {
        try {
            Long result = redisTemplate.opsForList().remove(addPrefix(key), count, value);
            log.debug("List remove successful: key={}, count={}", key, count);
            return result;
        } catch (Exception e) {
            log.error("List remove error: key={}, count={}, error={}", key, count, e.getMessage(), e);
            throw new RuntimeException("Redis list remove operation failed", e);
        }
    }

    @Override
    public void trim(String key, long start, long end) {
        try {
            redisTemplate.opsForList().trim(addPrefix(key), start, end);
            log.debug("List trim successful: key={}, start={}, end={}", key, start, end);
        } catch (Exception e) {
            log.error("List trim error: key={}, start={}, end={}, error={}", key, start, end, e.getMessage(), e);
            throw new RuntimeException("Redis list trim operation failed", e);
        }
    }

    @Override
    public <T> T rightPopAndLeftPush(String sourceKey, String destinationKey, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForList().rightPopAndLeftPush(addPrefix(sourceKey), addPrefix(destinationKey));
            log.debug("List rightPopAndLeftPush successful: sourceKey={}, destinationKey={}", sourceKey, destinationKey);
            return convertValue(value, clazz);
        } catch (Exception e) {
            log.error("List rightPopAndLeftPush error: sourceKey={}, destinationKey={}, error={}", sourceKey, destinationKey, e.getMessage(), e);
            throw new RuntimeException("Redis rightPopAndLeftPush operation failed", e);
        }
    }

    @Override
    public <T> T rightPopAndLeftPush(String sourceKey, String destinationKey, long timeout, TimeUnit timeUnit, Class<T> clazz) {
        try {
            Object value = redisTemplate.opsForList().rightPopAndLeftPush(addPrefix(sourceKey), addPrefix(destinationKey), timeout, timeUnit);
            log.debug("List blocking rightPopAndLeftPush successful: sourceKey={}, destinationKey={}", sourceKey, destinationKey);
            return convertValue(value, clazz);
        } catch (Exception e) {
            log.error("List blocking rightPopAndLeftPush error: sourceKey={}, destinationKey={}, error={}", sourceKey, destinationKey, e.getMessage(), e);
            throw new RuntimeException("Redis blocking rightPopAndLeftPush operation failed", e);
        }
    }

    /**
     * 将单个对象转换为指定类型
     */
    private <T> T convertValue(Object value, Class<T> clazz) {
        if (value == null) {
            return null;
        }
        if (clazz.isInstance(value)) {
            return clazz.cast(value);
        } else {
            return objectMapper.convertValue(value, clazz);
        }
    }

    /**
     * 将对象列表转换为指定类型的列表
     */
    private <T> List<T> convertList(List<Object> values, Class<T> clazz) {
        List<T> result = new ArrayList<>(values.size());
        for (Object value : values) {
            result.add(convertValue(value, clazz));
        }
        return result;
    }
}